using System;
using System.Collections.Generic;

namespace SmartSite.Frame
{

    class ValueOperating<T> where T : struct
    {
        readonly BitsVariable BitsVariable;
        readonly BitUnit Count;
        readonly Func<T> NewValueDelegate;
        readonly Func<T, byte> GetLowByteDelegate;
        readonly Func<T, int, T> MoveToLeftDelegate;
        readonly Func<T, int, T> MoveToRightDelegate;
        readonly Func<T, byte, T> AddDelegate;


        public ValueOperating(
            BitsVariable bitsVariable,
            BitUnit count,
            Func<T> newValueDelegate,
            Func<T, byte> getLowByteDelegate,
            Func<T, int, T> moveToLeftDelegate,
            Func<T, int, T> moveToRightDelegate,
            Func<T, byte, T> addDelegate
        )
        {
            BitsVariable = bitsVariable;
            Count = count;
            NewValueDelegate = newValueDelegate;
            GetLowByteDelegate = getLowByteDelegate;
            MoveToLeftDelegate = moveToLeftDelegate;
            MoveToRightDelegate = moveToRightDelegate;
            AddDelegate = addDelegate;
        }

        public ValueOperating<T> RestoreBits(out T value)
        {
            value = NewValueDelegate();
            foreach (BitsPart item in BitsVariable.BitsParts())
            {
                value = MoveToLeftDelegate(value, item.Count);
                value = AddDelegate(value, item.Value);
            }

            return this;
        }

        public ValueOperating<T> RestoreSign(ref T value)
        {
            if (Count > 1) // 小于 2 时, 无符号位
            {
                int index = 64 - Count;
                value = MoveToLeftDelegate(value, index);
                value = MoveToRightDelegate(value, index);
            }
            return this;
        }

        public ValueOperating<T> ToByteList(T value, out List<byte> bits)
        {
            bits = new List<byte>();
            for (int i = Count.CeilToByteUnit(); i > 0; i--)
            {
                bits.Insert(0, GetLowByteDelegate(value));
                value = MoveToRightDelegate(value, 8);
            }

            return this;
        }

        public ValueOperating<T> CopyToBitsVariable(List<byte> bits)
        {
            BitsVariable newBits = new BitsVariable(bits, (bits.Count << 3) - Count, Count);
            newBits.CopyTo(BitsVariable);
            return this;
        }
    }
}
